% Plot 2D contour over a grid using gmm method (adapted from original code
% used in novelty detection toolbox)
% INPUTS
% mix:  output from running Train_gmm() or Train_kde().
% data: matrix of size ndata x numftrs, numftrs == 2.
% params: a structure, parameters for setting grids; optional.
% contSymbol: a structure, set symbols for contour plotting; optional.
%
% See also: PLotGMMhist, PlotSVM2Dcont.m
%
% MAFPimentel, 27 May 2011

function fh = plot2Dcont(mix, test_nega, test_posi, params, contSymbol)

if nargin < 4
    % params.fullscr = 0; % 1: full screen. 0: normal screen.
    params.na = 100; % grid number on x-axis. na and nb affects the shape of the contour plot!
    params.nb = 100; % grid number on y-axis.
    params.nlevels = 100;
    params.thresh = 0.01; % an emperical threshold (usually not used)
end

% white for normal data, black for abnormal data; + for test data, . for training data, ^ for artificial data.
if nargin < 5
    contSymbol.trainNor = 'w.';
    contSymbol.svmSup = 'wo'; % support vectors in SVM
    contSymbol.testNor = 'w+';
    contSymbol.testAb = 'k+';
    contSymbol.artiNor = 'w^';
    contSymbol.artiAb = 'k^';
    contSymbol.contour = 'k';
    contSymbol.pointsize = 6; % 8 is too big. 2 is too small.
end

if ~isfield(params, 'na')           params.na = 100;      end
if ~isfield(params, 'nb')           params.nb = 100;      end
if ~isfield(params, 'nlevels')      params.nlevels = 100; end
if ~isfield(params, 'thresh')      params.thresh = 0.01;  end
if ~isfield(contSymbol, 'trainNor')         contSymbol.trainNor = 'w.';   end
if ~isfield(contSymbol, 'svmSup')           contSymbol.svmSup = 'wo';     end
if ~isfield(contSymbol, 'testNor')          contSymbol.testNor = 'w+';    end
if ~isfield(contSymbol, 'testAb')           contSymbol.testAb = 'k+';     end
if ~isfield(contSymbol, 'artiNor')          contSymbol.artiNor = 'w^';    end
if ~isfield(contSymbol, 'artiAb')           contSymbol.artiAb = 'k^';     end
if ~isfield(contSymbol, 'contour')           contSymbol.contour = 'k';    end
if ~isfield(contSymbol, 'pointsize')        contSymbol.pointsize = 6;     end

if size(test_nega, 2) == 1
    fprintf('Data have only 1 feature, hence no 2D contour is plotted. \n');
    return;
end

if size(test_nega, 2) > 2   
    mix.train = mix.train(:,1:2);
    test_nega = test_nega(:,1:2);
    test_posi = test_posi(:,1:2); % number of features == 2 now.
    fprintf('Data have > 2 features; only first two features are plotted.\n');
end


%% Generate 2D grids
alldata = [mix.train; test_nega; test_posi];
[xgrid, xgrida, xgridb] = Grid2D(alldata, params.na, params.nb);
ygrid_vec = Out_gmm(xgrid, mix);
ygrid = reshape(ygrid_vec, params.na, params.nb); % ygrid is na by nb; ygrid_vec is na*nb by 1.

%% plot 2D contour over grids
fh = figure('name', 'cont'); 
clf;
hold on;
[C,h] = contourf(xgrida, xgridb, ygrid, params.nlevels); % Filled 2D contour plot.
shading flat; 
colorbar;
colormap hsv; % used in Plotparzen for my thesis.
% colormap gray; % For IEEE conference.

% contVec = linspace(0, max(ygrid_vec), 10); % plot several contour.
contVec = [params.thresh, params.thresh]; % only plot threshold contour.
[cc,hh]=contour(xgrida,xgridb,ygrid,contVec, contSymbol.contour); % Contour graph of a matrix
clabel(cc,hh);


plot(mix.train(:,1), mix.train(:,2), contSymbol.trainNor, 'markersize', contSymbol.pointsize); % train data are all normal/negative.
if ~isempty(test_nega) % real test normal/negative.
    plot(test_nega(:,1), test_nega(:,2), contSymbol.testNor, 'markersize', contSymbol.pointsize);     
end

if ~isempty(test_posi) % real test abnormal/positive.
    plot(test_posi(:,1), test_posi(:,2), contSymbol.testAb, 'markersize', contSymbol.pointsize); 
end
hold off;